package cn.walls1717.wallsmall.product.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.walls1717.wallsmall.common.utils.PageUtils;
import cn.walls1717.wallsmall.common.utils.Query;
import cn.walls1717.wallsmall.product.dao.AttrAttrgroupRelationDao;
import cn.walls1717.wallsmall.product.dao.AttrDao;
import cn.walls1717.wallsmall.product.dao.AttrGroupDao;
import cn.walls1717.wallsmall.product.entity.*;
import cn.walls1717.wallsmall.product.service.*;
import cn.walls1717.wallsmall.product.vo.AttrRespVO;
import cn.walls1717.wallsmall.product.vo.AttrVO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static cn.walls1717.wallsmall.common.constant.ProductConstant.AttrEnum.ATTR_TYPE_BASE;
import static cn.walls1717.wallsmall.common.constant.ProductConstant.AttrEnum.ATTR_TYPE_SALE;

@Service("attrService")
public class AttrServiceImpl extends ServiceImpl<AttrDao, AttrEntity> implements AttrService {

    @Resource
    private AttrAttrgroupRelationService attrAttrgroupRelationService;
    @Resource
    private AttrAttrgroupRelationDao attrAttrgroupRelationDao;
    @Resource
    private CategoryService categoryService;
    @Resource
    private AttrGroupService attrGroupService;
    @Resource
    private AttrGroupDao attrGroupDao;
    @Resource
    private ProductAttrValueService productAttrValueService;

    /**
     * 分页展示，根据属性id或属性名称模糊查询
     *
     * @param params 分页参数，查询条件
     * @param catId 分类id
     * @param type base基本属性；sale销售属性
     * @return 分页数据
     */
    @Override
    public PageUtils listPages(Map<String, Object> params, Long catId, String type) {
        LambdaQueryWrapper<AttrEntity> lqw = new LambdaQueryWrapper<>();
        // 属性类型[0-销售属性，1-基本属性，2-既是销售属性又是基本属性]
        lqw.eq(AttrEntity::getAttrType,
            "base".equalsIgnoreCase(type) ? ATTR_TYPE_BASE.getCode() : ATTR_TYPE_SALE.getCode());
        // 如果分类id为0，那么表示查询所有，无需组装catelogId查询条件
        if (catId != 0) {
            lqw.eq(AttrEntity::getCatelogId, catId);
        }
        // 拼接查询条件，根据属性id或者属性名称查找
        String key = ((String)params.get("key"));
        if (!StrUtil.isEmpty(key)) {
            // WHERE catelogId=? and (attr_id = ? OR attr_name LIKE ?)
            lqw.and(obj -> obj.eq(AttrEntity::getAttrId, key).or().like(AttrEntity::getAttrName, key));
        }

        IPage<AttrEntity> page = page(new Query<AttrEntity>().getPage(params), lqw);
        PageUtils pageUtils = new PageUtils(page);
        // 设置分类名称与属性分组名称
        List<AttrRespVO> collect = page.getRecords().stream().map(this::getAttrRespVO).collect(Collectors.toList());
        // 将封装好的AttrRespVO集合重新设置为响应数据
        pageUtils.setList(collect);
        return pageUtils;
    }

    /**
     * 保存属性数据同时保存属性与属性分组关系
     *
     * @param attr 属性
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveAttrWithAttrAttrGroupRelation(AttrVO attr) {
        AttrEntity attrEntity = new AttrEntity();
        BeanUtil.copyProperties(attr, attrEntity);
        // 保存attr表数据
        save(attrEntity);

        // 当属性类型为基本类型时，属性设置属性分组时保存属性与分组关系
        if (ObjectUtil.equal(attr.getAttrType(), ATTR_TYPE_BASE.getCode()) && attr.getAttrGroupId() != null) {
            // 保存关联关系attr_attrgroup_relation表
            AttrAttrgroupRelationEntity attrAttrgroupRelationEntity = new AttrAttrgroupRelationEntity();
            attrAttrgroupRelationEntity.setAttrGroupId(attr.getAttrGroupId());
            attrAttrgroupRelationEntity.setAttrId(attrEntity.getAttrId());
            attrAttrgroupRelationService.save(attrAttrgroupRelationEntity);
        }
    }

    /**
     * 获取属性详细信息
     *
     * @param attrId 属性id
     * @return AttrRespVO
     */
    @Override
    public AttrRespVO getAttrInfo(Long attrId) {
        AttrEntity attr = getById(attrId);
        return getAttrRespVO(attr);
    }

    /**
     * 修改属性信息，同时修改属性与属性分组的关联关系
     *
     * @param attrVO 修改参数
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateAttrWithAttrAttrGroupRelation(AttrVO attrVO) {
        AttrEntity attr = new AttrEntity();
        BeanUtil.copyProperties(attrVO, attr);
        // 先修改attr表中的数据
        updateById(attr);

        // 如果类型为销售属性则不需要操作attr_attrGroup_relation表
        if (ObjectUtil.equal(attrVO.getAttrType(), ATTR_TYPE_SALE.getCode())) {
            return;
        }

        Long attrGroupId = attrVO.getAttrGroupId();
        Long attrId = attrVO.getAttrId();

        // 如果属性与属性分组关系表中没有数据，则添加关系；如果有数据则修改关系
        Long count =
            attrAttrgroupRelationService.lambdaQuery().eq(AttrAttrgroupRelationEntity::getAttrId, attrId).count();
        // 添加关系
        if (count == 0) {
            AttrAttrgroupRelationEntity attrAttrGroupRelation = new AttrAttrgroupRelationEntity();
            attrAttrGroupRelation.setAttrId(attrId);
            attrAttrGroupRelation.setAttrGroupId(attrGroupId);
            attrAttrgroupRelationService.save(attrAttrGroupRelation);
            return;
        }
        // 修改关系
        attrAttrgroupRelationService.lambdaUpdate().set(AttrAttrgroupRelationEntity::getAttrGroupId, attrGroupId)
            .eq(AttrAttrgroupRelationEntity::getAttrId, attrId).update();

    }

    /**
     * 获取属性分组关联的属性
     *
     *
     * @param attrGroupId 属性分组id
     * @return 所有属性
     */
    @Override
    public List<AttrEntity> listAttrsByAttrGroupId(Long attrGroupId) {
        List<AttrAttrgroupRelationEntity> attrAttrGroupRelations = attrAttrgroupRelationService.lambdaQuery()
            .eq(AttrAttrgroupRelationEntity::getAttrGroupId, attrGroupId).list();
        // 根据属性分组id没有查询出属性与属性分组关系，直接返回null
        if (attrAttrGroupRelations == null || attrAttrGroupRelations.size() == 0) {
            return null;
        }
        List<Long> attrIds =
            attrAttrGroupRelations.stream().map(AttrAttrgroupRelationEntity::getAttrId).collect(Collectors.toList());
        return listByIds(attrIds);
    }

    /**
     * 获取属性分组没有关联的其他属性
     *
     * @param params 分页条件与查询条件
     * @param attrGroupId 属性分组id
     * @return 分页数据
     */
    @Override
    public PageUtils listNoAttrsByAttrGroupId(Map<String, Object> params, Long attrGroupId) {
        AttrGroupEntity attrGroup = attrGroupService.getById(attrGroupId);
        LambdaQueryWrapper<AttrEntity> lqw = new LambdaQueryWrapper<>();
        Long catelogId = attrGroup.getCatelogId();
        // 必须查询出指定类别与销售属性的数据
        lqw.eq(AttrEntity::getCatelogId, catelogId).eq(AttrEntity::getAttrType, ATTR_TYPE_BASE.getCode());

        /*
         -> 通过catelogId拿到attrGroupId集合
         -> 通过此集合经过attr_attrGroup_relation表拿到attrId集合
         -> 再排除attrId的数据
         */
        List<Long> attrGroupIds = attrGroupDao.getAttrGroupIdsByCatelogId(catelogId);
        if (attrGroupIds != null && attrGroupIds.size() > 0) {
            List<Long> attrIds = attrAttrgroupRelationDao.listAttrIdsByAttrGroupIds(attrGroupIds);
            if (attrIds != null && attrIds.size() > 0) {
                /*
                 这样拿到的attrIds有两种情况：
                 1.已经关联本类别下其它分组的属性
                 2.已经关联到本分组的属性
                 所以需要使用 not in (attrIds)
                 */
                lqw.notIn(AttrEntity::getAttrId, attrIds);
            }
        }

        // 拼接查询条件，根据属性id或者属性名称查找
        String key = (String)params.get("key");
        if (key != null) {
            lqw.and(obj -> obj.eq(AttrEntity::getAttrId, key).or().like(AttrEntity::getAttrName, key));
        }

        // 封装分页数据
        IPage<AttrEntity> page = page(new Query<AttrEntity>().getPage(params));
        PageUtils pageUtils = new PageUtils(page);
        List<AttrEntity> list = list(lqw);
        pageUtils.setList(list);
        return pageUtils;
    }

    /**
     * 根据spuId查询商品属性
     *
     * @param spuId spuId
     * @return 商品属性集合
     */
    @Override
    public List<ProductAttrValueEntity> listProductAttrsBySpuId(Long spuId) {
        return productAttrValueService.lambdaQuery().eq(ProductAttrValueEntity::getSpuId, spuId).list();
    }

    /**
     * 根据attrId集合查找检索属性的attrId
     *
     * @param attrIds attrIds
     * @return 检索属性的attrId集合
     */
    @Override
    public List<Long> listSearchAttrIdsByAttIds(List<Long> attrIds) {
        return baseMapper.listSearchAttrIdsByAttIds(attrIds);
    }

    /**
     * 封装AttrRespVO
     *
     * @param attr AttrEntity
     * @return AttrRespVO
     */
    @NotNull
    private AttrRespVO getAttrRespVO(AttrEntity attr) {
        AttrRespVO attrRespVO = new AttrRespVO();
        BeanUtil.copyProperties(attr, attrRespVO);

        // 当类型为基本类型时设置属性分组id与name
        if (ObjectUtil.equal(attr.getAttrType(), ATTR_TYPE_BASE.getCode())) {
            AttrAttrgroupRelationEntity attrAttrgroupRelation = attrAttrgroupRelationService.lambdaQuery()
                .eq(AttrAttrgroupRelationEntity::getAttrId, attr.getAttrId()).one();
            if (attrAttrgroupRelation != null) {
                // 设置属性分组id
                Long attrGroupId = attrAttrgroupRelation.getAttrGroupId();
                if (attrGroupId != null) {
                    attrRespVO.setAttrGroupId(attrGroupId);
                }
                // 设置属性分组name
                AttrGroupEntity attrGroup = attrGroupService.getById(attrGroupId);
                if (attrGroup != null) {
                    attrRespVO.setGroupName(attrGroup.getAttrGroupName());
                }
            }
        }

        // 设置分类name
        Long catelogId = attr.getCatelogId();
        CategoryEntity category = categoryService.getById(catelogId);
        if (category != null) {
            attrRespVO.setCatelogName(category.getName());
        }

        // 设置分类层级路径[父/子/孙]
        Long[] catelogPath = categoryService.getCatalogPath(catelogId);
        attrRespVO.setCatelogPath(catelogPath);
        return attrRespVO;
    }

}